package com.example.service.aboutCollege.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.vo.request.*;
import com.example.vo.response.CollegeEnrollmentDTO;
import com.example.mapper.aboutCollege.CollegeEnrollmentMapper;
import com.example.mapper.aboutStudent.StudentMapper;
import com.example.pojo.aboutCollege.CollegeEnrollment;
import com.example.pojo.aboutStudent.Student;
import com.example.service.aboutCollege.CollegeEnrollmentService;
import com.example.service.aboutStudent.StudentService;
import com.example.vo.Result;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;

@Service
public class CollegeEnrollmentServiceImpl extends ServiceImpl<CollegeEnrollmentMapper, CollegeEnrollment> implements CollegeEnrollmentService {

    @Resource
    private StudentService studentService;

    @Resource
    private StudentMapper studentMapper;

    /**
     * 添加学院招生数据
     *
     * @param collegeEnrollDataList 学院招生数据集合
     * @return 是否添加成功
     */
    @Override
    public Result saveCollegeEnrollData(List<SaveCollegeEnrollData> collegeEnrollDataList) {

        for (SaveCollegeEnrollData collegeEnrollData : collegeEnrollDataList) {
            // 获取此年份，此学院的所有学生数据，统计出实际录取数量、第一志愿报考率、第一志愿录取率、覆盖省份数量
            String college = collegeEnrollData.getCollege();
            String grade = collegeEnrollData.getGrade();

            LambdaQueryWrapper<Student> studentLambdaQueryWrapper = new LambdaQueryWrapper<>();
            studentLambdaQueryWrapper.eq(Student::getGrade, grade);

            List<Student> totalStudentsByYear = studentService.list(studentLambdaQueryWrapper);// 指定学年所有学生

            // 符合年份、学院的学生数量 -- 实际录取人数
            studentLambdaQueryWrapper.eq(Student::getCollege, college);
            int studentNumByCollegeAndYear = Math.toIntExact(studentService.count(studentLambdaQueryWrapper));

            // 某学院本年度覆盖省份数量
            studentLambdaQueryWrapper.groupBy(Student::getOriginArea).select(Student::getOriginArea);
            int provincesNum = studentService.list(studentLambdaQueryWrapper).size();

            // 第一志愿录取率与第一志愿选择率，需统计所有学生的第一志愿，如果属于当前这个学院，则num++
            int firstChoiceNumByComputerCollege = 0;
            int haveFirstChoiceNum = 0;
            int sameNumByMajorWithFirstChoice = 0;

            for (Student student : totalStudentsByYear) {
                String firstChoice = student.getFirstChoice();
                if (!Objects.equals(firstChoice, "")) {
                    if (firstChoice.equals("软件工程")
                            || firstChoice.equals("计算机科学与技术")
                            || firstChoice.equals("网络工程")
                            || firstChoice.equals("大数据与数据科学")
                            || firstChoice.equals("计算机类")) {
                        firstChoiceNumByComputerCollege++;

                        if (firstChoice.equals(student.getMajor())) {
                            sameNumByMajorWithFirstChoice++;
                        }
                    }
                    haveFirstChoiceNum++;
                }
            }

            double firstChoiceRate = 0;
            double firstAdmitRate = 0;

            if (haveFirstChoiceNum != 0) {
                // 第一志愿选择率
                firstChoiceRate = (double) firstChoiceNumByComputerCollege / haveFirstChoiceNum;

                // 第一志愿录取率 -- 第一志愿与实际专业相同的学生
                firstAdmitRate = (double) sameNumByMajorWithFirstChoice / haveFirstChoiceNum;
            }


            CollegeEnrollment collegeEnrollment = new CollegeEnrollment();
            collegeEnrollment.setCollege(college);
            collegeEnrollment.setGrade(grade);
            collegeEnrollment.setPlannedEnrollment(collegeEnrollData.getPlannedEnrollment());
            collegeEnrollment.setActualEnrollment(studentNumByCollegeAndYear);
            collegeEnrollment.setProvincesCovered(provincesNum);
            collegeEnrollment.setFirstChoiceRate(firstChoiceRate);
            collegeEnrollment.setFirstAdmitRate(firstAdmitRate);

            super.save(collegeEnrollment);
        }

        return Result.success();
    }

    /**
     * 根据学院名字，获取近些年招生的数据
     *
     * @param collegeName 学院名称
     * @return 学院历年来招生数据
     */
    @Override
    public Result getCollegeData(String collegeName) {
        LambdaQueryWrapper<CollegeEnrollment> collegeEnrollmentLambdaQueryWrapper = new LambdaQueryWrapper<>();
        collegeEnrollmentLambdaQueryWrapper.eq(CollegeEnrollment::getCollege, collegeName);

        List<CollegeEnrollment> list = super.list(collegeEnrollmentLambdaQueryWrapper);

        List<CollegeEnrollmentDTO> collegeEnrollmentDTOS = BeanUtil.copyToList(list, CollegeEnrollmentDTO.class);

        return Result.success(collegeEnrollmentDTOS);
    }

    /**
     * @param collegeEnrollId 要删除的学院id
     * @return 是否删除成功
     */
    @Override
    public Result deleteCollegeData(Integer collegeEnrollId) {
        super.removeById(collegeEnrollId);

        return Result.success();
    }

    /**
     * 用于学生变化后，更新学院录取率等字段
     *
     * @param collegeName 学院名称
     * @return 是否更新成功
     */
    @Override
    public Result updateCollegeData(String collegeName, String grade) {

        LambdaQueryWrapper<Student> studentLambdaQueryWrapper = new LambdaQueryWrapper<>();
        studentLambdaQueryWrapper.eq(Student::getGrade, grade);

        // 指定学年的所有学生
        List<Student> students = studentService.list(studentLambdaQueryWrapper);

        // 第一志愿录取率与第一志愿选择率，需统计所有学生的第一志愿，如果属于当前这个学院，则num++
        int firstChoiceNumByComputerCollege = 0;
        int haveFirstChoiceNum = 0;
        int sameNumByMajorWithFirstChoice = 0;

        // 计算机学院学生人数
        int computerCollegeStudentNum = 0;

        HashSet<String> provinces = new HashSet<>();

        for (Student student : students) {
            String firstChoice = student.getFirstChoice();

            if (student.getCollege().equals("计算机学院")) {
                computerCollegeStudentNum++;
                provinces.add(student.getOriginArea());
            }

            if (!Objects.equals(firstChoice, "") && firstChoice != null) {
                if (firstChoice.equals("软件工程")
                        || firstChoice.equals("计算机科学与技术")
                        || firstChoice.equals("网络工程")
                        || firstChoice.equals("大数据与数据科学")
                        || firstChoice.equals("计算机类")) {
                    firstChoiceNumByComputerCollege++;

                    if (firstChoice.equals(student.getMajor())) {
                        sameNumByMajorWithFirstChoice++;
                    }
                }
                haveFirstChoiceNum++;
            }
        }

        double firstChoiceRate = 0;
        double firstAdmitRate = 0;

        if (haveFirstChoiceNum != 0) {
            // 第一志愿选择率
            firstChoiceRate = (double) firstChoiceNumByComputerCollege / haveFirstChoiceNum;

            // 第一志愿录取率 -- 第一志愿与实际专业相同的学生
            firstAdmitRate = (double) sameNumByMajorWithFirstChoice / haveFirstChoiceNum;
        }

        LambdaUpdateWrapper<CollegeEnrollment> collegeEnrollmentLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        collegeEnrollmentLambdaUpdateWrapper.eq(CollegeEnrollment::getCollege, collegeName)
                .eq(CollegeEnrollment::getGrade, grade)
                .set(CollegeEnrollment::getActualEnrollment, computerCollegeStudentNum)
                .set(CollegeEnrollment::getFirstChoiceRate, firstChoiceRate)
                .set(CollegeEnrollment::getFirstAdmitRate, firstAdmitRate)
                .set(CollegeEnrollment::getProvincesCovered, provinces.size());

        super.update(collegeEnrollmentLambdaUpdateWrapper);

        return Result.success();
    }

    /**
     * 获取指定专业的实际招生数....
     *
     * @param major 专业
     * @return 专业招生数据
     */
    @Override
    public Result getCollegeMajorData(String major) {
        ArrayList<CollegeMajorEnrollmentCondition> collegeMajorEnrollmentConditions = new ArrayList<>();

        List<MajorGradeSumTemp> majorGradePoints = studentMapper.getMajorGradePoints(major);

        for (MajorGradeSumTemp majorGradePoint : majorGradePoints) {
            CollegeMajorEnrollmentCondition collegeMajorEnrollmentCondition = new CollegeMajorEnrollmentCondition();
            // 专业/年级/平均分/最高分/最低分/学生数量
            collegeMajorEnrollmentCondition.setMajor(major);
            collegeMajorEnrollmentCondition.setGrade(majorGradePoint.getGrade());
            collegeMajorEnrollmentCondition.setAvgPoints(majorGradePoint.getAvgPoints());
            collegeMajorEnrollmentCondition.setMaxPoints(majorGradePoint.getMaxPoints());
            collegeMajorEnrollmentCondition.setMinPoints(majorGradePoint.getMinPoints());
            collegeMajorEnrollmentCondition.setEnrollmentNum(majorGradePoint.getSum());

            // 第一志愿录取率/第一志愿选择率
            String grade = majorGradePoint.getGrade();

            LambdaQueryWrapper<Student> studentLambdaQueryWrapper = new LambdaQueryWrapper<>();
            studentLambdaQueryWrapper.eq(Student::getGrade, grade);

            // 指定年度的学生数量
            long totalNumsByGrade = studentService.count(studentLambdaQueryWrapper);

            // 指定年度，第一志愿选择指定专业的学生数量
            studentLambdaQueryWrapper.eq(Student::getFirstChoice, major);
            long firstChoiceNumByMajor = studentService.count(studentLambdaQueryWrapper);

            // 第一志愿选择指定专业，且录取专业是第一志愿的学生数量
            studentLambdaQueryWrapper.eq(Student::getMajor, major);
            long numByChoiceAndEnroll = studentService.count(studentLambdaQueryWrapper);

            // 第一志愿选择率 - 指定年度，第一志愿选择指定专业的学生数量 / 指定年度的学生数量
            double firstChoiceChooseRate = (double) firstChoiceNumByMajor / totalNumsByGrade;

            // 第一志愿录取率 - 第一志愿选择指定专业，且录取专业是第一志愿的学生数量 / 指定年度，第一志愿选择指定专业的学生数量
            double firstChoiceAdmitRate = 0.0;

            if(firstChoiceChooseRate != 0.0) {
                firstChoiceAdmitRate = (double) numByChoiceAndEnroll / firstChoiceNumByMajor;
            }


            collegeMajorEnrollmentCondition.setFirstChoiceRate(firstChoiceChooseRate);
            collegeMajorEnrollmentCondition.setFirstAdmitRate(firstChoiceAdmitRate);

            collegeMajorEnrollmentConditions.add(collegeMajorEnrollmentCondition);
        }


        return Result.success(collegeMajorEnrollmentConditions);
    }
}
